# -*- encoding: utf-8 -*-
"""
File Name: monitoring_pipeline_interface
Description: Defines the MonitorPipLineInterface class which serves as an interface for monitoring pipelines.
Author : 'lirui'
Date: 10/24/2024
Contact: marjey_lee@163.com
Change Activity:
10/24/2024:
"""
from abc import abstractmethod, ABC
from threading import Thread

import ll
from projects.monitoring.common.do.alarm import Alarm
from projects.monitoring.common.do.monitor_redis_data import MonitorRedisData
from projects.monitoring.common.utils.redis_problem_publishers_manager import RedisProblemsPublishersManager


class MonitorPipLineInterface(Thread, ABC):
    """
    An interface for monitoring pipelines.

    Attributes:
        monitoring_type (str): The type of monitoring.
        monitor_type (str): The specific monitor type.
    """

    def __init__(self, monitor_type, monitor_interval=1):
        """
        Initializes the MonitorPipLineInterface with the given monitor type.

        Args:
            monitor_type (str): The type of monitoring.
        """
        super().__init__()
        self.monitoring_type = monitor_type
        self.monitor_interval = monitor_interval
        self.monitor_type = None
        self.is_running_normal = True  # True if the monitoring pipeline is running normally, False otherwise.
        self.error_msg = ''

    def get_error_msg(self):
        return self.error_msg

    def health_check(self):
        """
        Health check method to check if the monitoring pipeline is running normally.

        Returns:
            bool: True if the monitoring pipeline is running normally, False otherwise.
        """
        return self.is_running_normal

    def __call__(self):
        """
        Executes the monitoring pipeline by loading, formatting, and sending alarms to Redis.
        """
        original_alarms = self._load_original_alarms_wrapper()
        formated_alarms = self._format_alarms_wrapper(original_alarms)
        self._send_alarm_to_redis(formated_alarms)

    def run(self):
        """
        Runs the monitoring pipeline.
        """
        while True:
            try:
                ll.get_logger().info('Start to monitor zabbix containers.')
                self()
                self.is_running_normal = True
                ll.sleep(self.monitor_interval)
            except Exception as e:
                ll.get_logger().error(e)
                self.error_msg = str(e)
                self.is_running_normal = False
                ll.sleep(60)

    @abstractmethod
    def _load_original_alarms(self) -> list:
        """
        Abstract method to load original alarms. Must be implemented by subclasses.
        """
        pass

    @abstractmethod
    def _format_alarms(self, original_alarms) -> list[Alarm]:
        """
        Abstract method to format alarms. Must be implemented by subclasses.

        Args:
            original_alarms (list): A list of original alarms.

        Returns:
            list: A list of formatted alarms.
        """
        pass

    def _send_alarm_to_redis(self, formated_alarms):
        """
        Sends the formatted alarms to Redis.

        Args:
            formated_alarms (list): A list of formatted alarms.
        """
        redis_data = MonitorRedisData(self.monitoring_type)
        redis_data.is_monitor_success = True
        redis_data.monitor_message = 'success'
        redis_data.data = formated_alarms
        redis_data.send_data_timestamp = ll.TimeUtil.get_current_timestamp()
        ll.get_logger().info(f'Publish {len(formated_alarms)} alarms to redis')
        RedisProblemsPublishersManager.publish(key=self.monitoring_type, content=redis_data.dumps())

    def _load_original_alarms_wrapper(self) -> list:
        """
        Wrapper method to load original alarms with error handling.

        Returns:
            list: A list of original alarms or an empty list if an error occurs.
        """
        data = self._load_original_alarms()
        return data

    def _format_alarms_wrapper(self, original_alarms):
        """
        Wrapper method to format alarms with error handling.

        Args:
            original_alarms (list): A list of original alarms.

        Returns:
            list: A list of formatted alarms or an empty list if an error occurs.
        """
        data = self._format_alarms(original_alarms)
        format_data = []
        for d in data:
            assert isinstance(d, Alarm)
            d.alarm_source = self.monitoring_type
            format_data.append(d.to_json())
        return format_data
    #
    # def _build_error_data(self, e):
    #     """
    #     Builds error data and logs the error.
    #
    #     Args:
    #         e (Exception): The exception that occurred.
    #     """
    #     self.redis_data.is_monitor_success = False
    #     self.redis_data.monitor_message = str(e)
    #     ll.get_logger().error(e)
